#pragma once
#include <mutex>
#include <thread>
#include <condition_variable>
#include <iostream>
#include <functional>
#include <queue>
#include <vector>
#include <string>
#include <memory>
#include <unistd.h>
// using task_t = std::function<void()>;

/****************
 *      实现简易的线程池
 * ******************** */

template <class T>
class ThreadPool
{
public:
    static ThreadPool<T>* GetInstance()
    {
        if (!instance)
        {
            std::unique_lock<std::mutex> lock(ThreadPool::MTX);
            if (!instance)
            {
                std::cout << "创建单例" << std::endl;
                instance = new ThreadPool<T>;
            }
        }
        return instance;
    }

    void Start()
    {
        for (int i = 0; i < _threadnum; i++)
        {
            _works[i] = std::thread([this, i]()
                                    { ThreadRoutine("thread-" + std::to_string(i)); });
        }
    }

    void ThreadRoutine(std::string name)
    {
        while (true)
        {
            T t;
            {
                std::unique_lock<std::mutex> lock(_mutex);
                while (_q.empty())
                {
                    _cv.wait(lock);
                }
                t = _q.front();
                _q.pop();
            }
            std::cout << name << "被唤醒，执行任务" << std::endl;
            t();
        }
    }

    void Push(const T &t)
    {
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _q.push(t);
        }
        _cv.notify_one();
        std::cout << "放任务" << std::endl;
    }

private:
    ThreadPool(int size = 5)
        : _threadnum(size)
    {
        _works.resize(_threadnum);
    }

    ThreadPool& operator = (const ThreadPool &) = delete;
    ThreadPool(const ThreadPool &) = delete;

private:
    int _threadnum;
    std::vector<std::thread> _works;
    std::mutex _mutex;
    std::condition_variable _cv;
    std::queue<T> _q;

    static ThreadPool<T> *instance;
    static std::mutex MTX;
};

template <class T>
ThreadPool<T> *ThreadPool<T>::instance = nullptr;
template <class T>
std::mutex ThreadPool<T>::MTX;